import time

import loguru
import requests
from celerytask import app

from config import kLocUserImagesPath, kSourceVideosFrame, kUserSwapperFaceFrames, kFontPath
from utils.image_utils import process_user_image
from utils.video_utils import split_video_into_frames, 加水印
from loguru import logger
from utils import face_swapper_process
# from tybase.tools.video_utils import synthesize_video
from utils.cloud_utils import upload_file_to_aliyun, transform_path, upload_file_to_qiniu
from tybase.tools.image_utils import url_to_md5
from tybase.tools.image_utils import delete_file_or_directory
from uuid import uuid4
from utils.cloud_utils import notify_cloud_v2

# 重写了`synthesize_video`这个方法,加入了音频文件如果不存在就不会合成
def synthesize_video(image_directory, audio_path, output_path, frame_rate, crf=20, frame_name="frame_%04d.png"):
    '''
    from tybase.tools.video_utils import synthesize_video

    :param image_directory: 图片帧的目录
    :param audio_path:  音频文件的路径
    :param output_path:  输出视频的路径
    :param frame_rate: 视频的帧率
    :param crf:  视频的质量,最佳是23,18-20是无损的,数字越小,质量越高,但是文件越大
    :param frame_name: 需要合成的图片帧的命名格式
    :return: 视频合成以后的路径
    '''
    import os
    import subprocess

    # 构建图像文件路径，按照给定的命名格式
    input_images = os.path.join(image_directory, frame_name)

    # 使用 ffmpeg 命令合成视频
    command = ['ffmpeg',
               '-framerate', str(frame_rate),  # 设置帧率
               '-i', input_images]  # 输入图片文件路径

    # 检查音频文件是否存在，如果存在，则添加相关的参数
    if os.path.exists(audio_path):
        command.extend(['-i', audio_path])
        command.extend(['-strict', 'experimental'])
        command.extend(['-map', '0', '-map', '1'])  # 明确指定映射顺序，0代表第一个输入（图像），1代表第二个输入（音频）
        

    command.extend(['-c:v', 'libx264',  # 视频编码格式
                    '-pix_fmt', 'yuv420p',  # 设置像素格式
                    '-crf', f'{crf}',  # 设置质量，数字越小质量越高
                    '-y', output_path])  # 输出视频文件路径

    # 执行命令
    subprocess.run(command)
    return output_path



def notify(task):
    url = "http://api.gpuhub.xiaolubi.com/task/queue/completion"  # 修改了gpu的地址
    headers = {
        "TOKEN": "inUVBuypkgdmm5ym6l3XiIMwenb7SKQu"
    }
    data = {
        "queue_id": task.id,
        "status": 100 if task.status == "completed" else 250,
        "error_message": ""
    }
    try:
        if not task.result:
            logger.error(f"task的result为空")
            data["convert_url"] = ""
            data["status"] = 250
            data["error_message"] = "其他错误"
        else:
            data["convert_url"] = task.result["ty_path"]
            if task.status == "failed":
                data["status"] = 250
            elif task.result["verify_face"] is False:
                data["status"] = 250
                data["error_message"] = task.result["error_message"]
            elif data["error_message"]:
                data["status"] = 250

    except Exception as e:
        data["convert_url"] = ""
        data["status"] = 250
        data["error_message"] = f"系统其他错误{str(e)[:200]}"
        import traceback
        traceback.print_exc()
        logger.error(f'Notify failed due to: {str(e)}')

    # 做3次通知的尝试
    for i in range(3):
        try:
            response = requests.post(url, json=data, headers=headers)
            logger.success(f"{data['convert_url']} -> {response.status_code} -> 通知成功!")
            logger.info(f"data: {data}")
            logger.info(f"result: {task.result}")
            break
        except:
            time.sleep(1)
            print("失败...开始尝试重新尝试..")
            continue



# 人脸验证的api流程
preprocess_source_images_v2 = app.tasks['celerytask.tasks.preprocess_source_images_v2']
process_workflow_V3 = app.tasks['celerytask.tasks.start_V3']

# 视频分割
async_split_video_into_frames = app.tasks["workflows.workflows_base.async_split_video_into_frames"]
post_process_task = app.tasks["workflows.workflows_base.post_process_task"]
process_images_many_face_task = app.tasks["workflows.workflows_base.process_images_many_face_task"]
callback = app.tasks["workflows.workflows_base.callback"]

from workflows.workflows_base import async_split_video_into_frames

# 视频换脸流程
def 视频_换脸(视频url, 用户图片url, 帧数, 水印, oss_name="ali"):
    try:
        # 这个步骤其实不用去管
        loc_user_path_path = process_user_image(用户图片url, user_images_name=kLocUserImagesPath, max_dimension=350)
    except Exception as e:
        # 这里可以发一个通知
        return {
            "video_loc_frame_path": 视频url,
            "loc_user_path_path": 用户图片url,
            "verify_face": False,
            "ty_path": "",
            "error_message": "下载用户图片失败"
        }

    # 提取本地的视频目录
    try:
        frame_name = "frame_%04d.jpg"
        # 这里是用异步任务分割就可以
        # 针对本地的目录进行视频的分割
        unique_task_id = str(uuid4())
        # 这里改成同步 (只在入口机器上执行)
        logger.info(f"开始分割视频")
        split_item = async_split_video_into_frames(
                                            **{
                                                'video_url': 视频url, 
                                                'frame_rate': 帧数, 
                                                'frame_name': frame_name, 
                                                'save_path': kSourceVideosFrame,
                                                'task_id': unique_task_id
                                            }
                                            )
        video_loc_frame_path = split_item["video_loc_frame_path"]

        output_directory_name = face_swapper_process.process_images(loc_user_path_path, video_loc_frame_path,
                                                                    f"{video_loc_frame_path}_{int(time.time())}")
        # # 输出的目录,
        output_path = kUserSwapperFaceFrames + f"/{url_to_md5(视频url).split('.')[0]}_{int(time.time())}.mp4"
        
        requests_data = {"target_video":视频url}

        post_res = post_process_task.apply_async(
            kwargs={
                "_ignored_result":None,
                "output_directory_name":output_directory_name,
                "video_loc_frame_path":video_loc_frame_path,
                "requests_data": requests_data,
                "帧数":帧数,
                "frame_name":frame_name,
                "水印":水印,
                "oss_name":oss_name,
                "task_id":unique_task_id
            }
        ).get(timeout=30)
        
        return post_res

    except Exception as e:
        import traceback
        traceback.print_exc()
        return {}
        
    finally:
        delete_file_or_directory(loc_user_path_path)




if __name__ == '__main__':
    from tybase.tools.Task import TaskRunner

    视频_换脸("http://usfile.chaotuapp.com/upload/sync/ff0e6f50ea9d41b40164eb719139ba9b.mp4",
              "http://usfile.chaotuapp.com/upload/android/1691556085061/404543.jpg",
              5,
              水印=False
              )
    # 创建后台任务
    # task = TaskRunner.Task(视频_换脸, {'param1': 'value1', 'param2': 'value2'}, callback=notify)
